"""
Comprehensive unit tests for App models.

This test suite covers:
- App configuration validation
- App-Message relationships
- Conversation model integrity
- Annotation model relationships
"""

import json
from datetime import UTC, datetime
from decimal import Decimal
from unittest.mock import MagicMock, patch
from uuid import uuid4

import pytest

from models.model import (
    App,
    AppAnnotationHitHistory,
    AppAnnotationSetting,
    AppMode,
    AppModelConfig,
    Conversation,
    IconType,
    Message,
    MessageAnnotation,
    Site,
)


class TestAppModelValidation:
    """Test suite for App model validation and basic operations."""

    def test_app_creation_with_required_fields(self):
        """Test creating an app with all required fields."""
        # Arrange
        tenant_id = str(uuid4())
        created_by = str(uuid4())

        # Act
        app = App(
            tenant_id=tenant_id,
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=False,
            created_by=created_by,
        )

        # Assert
        assert app.name == "Test App"
        assert app.tenant_id == tenant_id
        assert app.mode == AppMode.CHAT
        assert app.enable_site is True
        assert app.enable_api is False
        assert app.created_by == created_by

    def test_app_creation_with_optional_fields(self):
        """Test creating an app with optional fields."""
        # Arrange & Act
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.COMPLETION,
            enable_site=True,
            enable_api=True,
            created_by=str(uuid4()),
            description="Test description",
            icon_type=IconType.EMOJI,
            icon="🤖",
            icon_background="#FF5733",
            is_demo=True,
            is_public=False,
            api_rpm=100,
            api_rph=1000,
        )

        # Assert
        assert app.description == "Test description"
        assert app.icon_type == IconType.EMOJI
        assert app.icon == "🤖"
        assert app.icon_background == "#FF5733"
        assert app.is_demo is True
        assert app.is_public is False
        assert app.api_rpm == 100
        assert app.api_rph == 1000

    def test_app_mode_validation(self):
        """Test app mode enum values."""
        # Assert
        expected_modes = {
            "chat",
            "completion",
            "workflow",
            "advanced-chat",
            "agent-chat",
            "channel",
            "rag-pipeline",
        }
        assert {mode.value for mode in AppMode} == expected_modes

    def test_app_mode_value_of(self):
        """Test AppMode.value_of method."""
        # Act & Assert
        assert AppMode.value_of("chat") == AppMode.CHAT
        assert AppMode.value_of("completion") == AppMode.COMPLETION
        assert AppMode.value_of("workflow") == AppMode.WORKFLOW

        with pytest.raises(ValueError, match="invalid mode value"):
            AppMode.value_of("invalid_mode")

    def test_icon_type_validation(self):
        """Test icon type enum values."""
        # Assert
        assert {t.value for t in IconType} == {"image", "emoji"}

    def test_app_desc_or_prompt_with_description(self):
        """Test desc_or_prompt property when description exists."""
        # Arrange
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=False,
            created_by=str(uuid4()),
            description="App description",
        )

        # Act
        result = app.desc_or_prompt

        # Assert
        assert result == "App description"

    def test_app_desc_or_prompt_without_description(self):
        """Test desc_or_prompt property when description is empty."""
        # Arrange
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=False,
            created_by=str(uuid4()),
            description="",
        )

        # Mock app_model_config property
        with patch.object(App, "app_model_config", new_callable=lambda: property(lambda self: None)):
            # Act
            result = app.desc_or_prompt

            # Assert
            assert result == ""

    def test_app_is_agent_property_false(self):
        """Test is_agent property returns False when not configured as agent."""
        # Arrange
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=False,
            created_by=str(uuid4()),
        )

        # Mock app_model_config to return None
        with patch.object(App, "app_model_config", new_callable=lambda: property(lambda self: None)):
            # Act
            result = app.is_agent

            # Assert
            assert result is False

    def test_app_mode_compatible_with_agent(self):
        """Test mode_compatible_with_agent property."""
        # Arrange
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=False,
            created_by=str(uuid4()),
        )

        # Mock is_agent to return False
        with patch.object(App, "is_agent", new_callable=lambda: property(lambda self: False)):
            # Act
            result = app.mode_compatible_with_agent

            # Assert
            assert result == AppMode.CHAT


class TestAppModelConfig:
    """Test suite for AppModelConfig model."""

    def test_app_model_config_creation(self):
        """Test creating an AppModelConfig."""
        # Arrange
        app_id = str(uuid4())
        created_by = str(uuid4())

        # Act
        config = AppModelConfig(
            app_id=app_id,
            provider="openai",
            model_id="gpt-4",
            created_by=created_by,
        )

        # Assert
        assert config.app_id == app_id
        assert config.provider == "openai"
        assert config.model_id == "gpt-4"
        assert config.created_by == created_by

    def test_app_model_config_with_configs_json(self):
        """Test AppModelConfig with JSON configs."""
        # Arrange
        configs = {"temperature": 0.7, "max_tokens": 1000}

        # Act
        config = AppModelConfig(
            app_id=str(uuid4()),
            provider="openai",
            model_id="gpt-4",
            created_by=str(uuid4()),
            configs=configs,
        )

        # Assert
        assert config.configs == configs

    def test_app_model_config_model_dict_property(self):
        """Test model_dict property."""
        # Arrange
        model_data = {"provider": "openai", "name": "gpt-4"}
        config = AppModelConfig(
            app_id=str(uuid4()),
            provider="openai",
            model_id="gpt-4",
            created_by=str(uuid4()),
            model=json.dumps(model_data),
        )

        # Act
        result = config.model_dict

        # Assert
        assert result == model_data

    def test_app_model_config_model_dict_empty(self):
        """Test model_dict property when model is None."""
        # Arrange
        config = AppModelConfig(
            app_id=str(uuid4()),
            provider="openai",
            model_id="gpt-4",
            created_by=str(uuid4()),
            model=None,
        )

        # Act
        result = config.model_dict

        # Assert
        assert result == {}

    def test_app_model_config_suggested_questions_list(self):
        """Test suggested_questions_list property."""
        # Arrange
        questions = ["What can you do?", "How does this work?"]
        config = AppModelConfig(
            app_id=str(uuid4()),
            provider="openai",
            model_id="gpt-4",
            created_by=str(uuid4()),
            suggested_questions=json.dumps(questions),
        )

        # Act
        result = config.suggested_questions_list

        # Assert
        assert result == questions

    def test_app_model_config_annotation_reply_dict_disabled(self):
        """Test annotation_reply_dict when annotation is disabled."""
        # Arrange
        config = AppModelConfig(
            app_id=str(uuid4()),
            provider="openai",
            model_id="gpt-4",
            created_by=str(uuid4()),
        )

        # Mock database query to return None
        with patch("models.model.db.session.query") as mock_query:
            mock_query.return_value.where.return_value.first.return_value = None

            # Act
            result = config.annotation_reply_dict

            # Assert
            assert result == {"enabled": False}


class TestConversationModel:
    """Test suite for Conversation model integrity."""

    def test_conversation_creation_with_required_fields(self):
        """Test creating a conversation with required fields."""
        # Arrange
        app_id = str(uuid4())
        from_end_user_id = str(uuid4())

        # Act
        conversation = Conversation(
            app_id=app_id,
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=from_end_user_id,
        )

        # Assert
        assert conversation.app_id == app_id
        assert conversation.mode == AppMode.CHAT
        assert conversation.name == "Test Conversation"
        assert conversation.status == "normal"
        assert conversation.from_source == "api"
        assert conversation.from_end_user_id == from_end_user_id

    def test_conversation_with_inputs(self):
        """Test conversation inputs property."""
        # Arrange
        inputs = {"query": "Hello", "context": "test"}
        conversation = Conversation(
            app_id=str(uuid4()),
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=str(uuid4()),
        )
        conversation._inputs = inputs

        # Act
        result = conversation.inputs

        # Assert
        assert result == inputs

    def test_conversation_inputs_setter(self):
        """Test conversation inputs setter."""
        # Arrange
        conversation = Conversation(
            app_id=str(uuid4()),
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=str(uuid4()),
        )
        inputs = {"query": "Hello", "context": "test"}

        # Act
        conversation.inputs = inputs

        # Assert
        assert conversation._inputs == inputs

    def test_conversation_summary_or_query_with_summary(self):
        """Test summary_or_query property when summary exists."""
        # Arrange
        conversation = Conversation(
            app_id=str(uuid4()),
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=str(uuid4()),
            summary="Test summary",
        )

        # Act
        result = conversation.summary_or_query

        # Assert
        assert result == "Test summary"

    def test_conversation_summary_or_query_without_summary(self):
        """Test summary_or_query property when summary is empty."""
        # Arrange
        conversation = Conversation(
            app_id=str(uuid4()),
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=str(uuid4()),
            summary=None,
        )

        # Mock first_message to return a message with query
        mock_message = MagicMock()
        mock_message.query = "First message query"
        with patch.object(Conversation, "first_message", new_callable=lambda: property(lambda self: mock_message)):
            # Act
            result = conversation.summary_or_query

            # Assert
            assert result == "First message query"

    def test_conversation_in_debug_mode(self):
        """Test in_debug_mode property."""
        # Arrange
        conversation = Conversation(
            app_id=str(uuid4()),
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=str(uuid4()),
            override_model_configs='{"model": "gpt-4"}',
        )

        # Act
        result = conversation.in_debug_mode

        # Assert
        assert result is True

    def test_conversation_to_dict_serialization(self):
        """Test conversation to_dict method."""
        # Arrange
        app_id = str(uuid4())
        from_end_user_id = str(uuid4())
        conversation = Conversation(
            app_id=app_id,
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=from_end_user_id,
            dialogue_count=5,
        )
        conversation.id = str(uuid4())
        conversation._inputs = {"query": "test"}

        # Act
        result = conversation.to_dict()

        # Assert
        assert result["id"] == conversation.id
        assert result["app_id"] == app_id
        assert result["mode"] == AppMode.CHAT
        assert result["name"] == "Test Conversation"
        assert result["status"] == "normal"
        assert result["from_source"] == "api"
        assert result["from_end_user_id"] == from_end_user_id
        assert result["dialogue_count"] == 5
        assert result["inputs"] == {"query": "test"}


class TestMessageModel:
    """Test suite for Message model and App-Message relationships."""

    def test_message_creation_with_required_fields(self):
        """Test creating a message with required fields."""
        # Arrange
        app_id = str(uuid4())
        conversation_id = str(uuid4())

        # Act
        message = Message(
            app_id=app_id,
            conversation_id=conversation_id,
            query="What is AI?",
            message={"role": "user", "content": "What is AI?"},
            answer="AI stands for Artificial Intelligence.",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
        )

        # Assert
        assert message.app_id == app_id
        assert message.conversation_id == conversation_id
        assert message.query == "What is AI?"
        assert message.answer == "AI stands for Artificial Intelligence."
        assert message.currency == "USD"
        assert message.from_source == "api"

    def test_message_with_inputs(self):
        """Test message inputs property."""
        # Arrange
        inputs = {"query": "Hello", "context": "test"}
        message = Message(
            app_id=str(uuid4()),
            conversation_id=str(uuid4()),
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
        )
        message._inputs = inputs

        # Act
        result = message.inputs

        # Assert
        assert result == inputs

    def test_message_inputs_setter(self):
        """Test message inputs setter."""
        # Arrange
        message = Message(
            app_id=str(uuid4()),
            conversation_id=str(uuid4()),
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
        )
        inputs = {"query": "Hello", "context": "test"}

        # Act
        message.inputs = inputs

        # Assert
        assert message._inputs == inputs

    def test_message_in_debug_mode(self):
        """Test message in_debug_mode property."""
        # Arrange
        message = Message(
            app_id=str(uuid4()),
            conversation_id=str(uuid4()),
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
            override_model_configs='{"model": "gpt-4"}',
        )

        # Act
        result = message.in_debug_mode

        # Assert
        assert result is True

    def test_message_metadata_dict_property(self):
        """Test message_metadata_dict property."""
        # Arrange
        metadata = {"retriever_resources": ["doc1", "doc2"], "usage": {"tokens": 100}}
        message = Message(
            app_id=str(uuid4()),
            conversation_id=str(uuid4()),
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
            message_metadata=json.dumps(metadata),
        )

        # Act
        result = message.message_metadata_dict

        # Assert
        assert result == metadata

    def test_message_metadata_dict_empty(self):
        """Test message_metadata_dict when metadata is None."""
        # Arrange
        message = Message(
            app_id=str(uuid4()),
            conversation_id=str(uuid4()),
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
            message_metadata=None,
        )

        # Act
        result = message.message_metadata_dict

        # Assert
        assert result == {}

    def test_message_to_dict_serialization(self):
        """Test message to_dict method."""
        # Arrange
        app_id = str(uuid4())
        conversation_id = str(uuid4())
        now = datetime.now(UTC)

        message = Message(
            app_id=app_id,
            conversation_id=conversation_id,
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            total_price=Decimal("0.0003"),
            currency="USD",
            from_source="api",
            status="normal",
        )
        message.id = str(uuid4())
        message._inputs = {"query": "test"}
        message.created_at = now
        message.updated_at = now

        # Act
        result = message.to_dict()

        # Assert
        assert result["id"] == message.id
        assert result["app_id"] == app_id
        assert result["conversation_id"] == conversation_id
        assert result["query"] == "Test query"
        assert result["answer"] == "Test answer"
        assert result["status"] == "normal"
        assert result["from_source"] == "api"
        assert result["inputs"] == {"query": "test"}
        assert "created_at" in result
        assert "updated_at" in result

    def test_message_from_dict_deserialization(self):
        """Test message from_dict method."""
        # Arrange
        message_id = str(uuid4())
        app_id = str(uuid4())
        conversation_id = str(uuid4())
        data = {
            "id": message_id,
            "app_id": app_id,
            "conversation_id": conversation_id,
            "model_id": "gpt-4",
            "inputs": {"query": "test"},
            "query": "Test query",
            "message": {"role": "user", "content": "Test"},
            "answer": "Test answer",
            "total_price": Decimal("0.0003"),
            "status": "normal",
            "error": None,
            "message_metadata": {"usage": {"tokens": 100}},
            "from_source": "api",
            "from_end_user_id": None,
            "from_account_id": None,
            "created_at": "2024-01-01T00:00:00",
            "updated_at": "2024-01-01T00:00:00",
            "agent_based": False,
            "workflow_run_id": None,
        }

        # Act
        message = Message.from_dict(data)

        # Assert
        assert message.id == message_id
        assert message.app_id == app_id
        assert message.conversation_id == conversation_id
        assert message.query == "Test query"
        assert message.answer == "Test answer"


class TestMessageAnnotation:
    """Test suite for MessageAnnotation and annotation relationships."""

    def test_message_annotation_creation(self):
        """Test creating a message annotation."""
        # Arrange
        app_id = str(uuid4())
        conversation_id = str(uuid4())
        message_id = str(uuid4())
        account_id = str(uuid4())

        # Act
        annotation = MessageAnnotation(
            app_id=app_id,
            conversation_id=conversation_id,
            message_id=message_id,
            question="What is AI?",
            content="AI stands for Artificial Intelligence.",
            account_id=account_id,
        )

        # Assert
        assert annotation.app_id == app_id
        assert annotation.conversation_id == conversation_id
        assert annotation.message_id == message_id
        assert annotation.question == "What is AI?"
        assert annotation.content == "AI stands for Artificial Intelligence."
        assert annotation.account_id == account_id

    def test_message_annotation_without_message_id(self):
        """Test creating annotation without message_id."""
        # Arrange
        app_id = str(uuid4())
        account_id = str(uuid4())

        # Act
        annotation = MessageAnnotation(
            app_id=app_id,
            question="What is AI?",
            content="AI stands for Artificial Intelligence.",
            account_id=account_id,
        )

        # Assert
        assert annotation.app_id == app_id
        assert annotation.message_id is None
        assert annotation.conversation_id is None
        assert annotation.question == "What is AI?"
        assert annotation.content == "AI stands for Artificial Intelligence."

    def test_message_annotation_hit_count_default(self):
        """Test annotation hit_count default value."""
        # Arrange
        annotation = MessageAnnotation(
            app_id=str(uuid4()),
            question="Test question",
            content="Test content",
            account_id=str(uuid4()),
        )

        # Act & Assert - default value is set by database
        # Model instantiation doesn't set server defaults
        assert hasattr(annotation, "hit_count")


class TestAppAnnotationSetting:
    """Test suite for AppAnnotationSetting model."""

    def test_app_annotation_setting_creation(self):
        """Test creating an app annotation setting."""
        # Arrange
        app_id = str(uuid4())
        collection_binding_id = str(uuid4())
        created_user_id = str(uuid4())
        updated_user_id = str(uuid4())

        # Act
        setting = AppAnnotationSetting(
            app_id=app_id,
            score_threshold=0.8,
            collection_binding_id=collection_binding_id,
            created_user_id=created_user_id,
            updated_user_id=updated_user_id,
        )

        # Assert
        assert setting.app_id == app_id
        assert setting.score_threshold == 0.8
        assert setting.collection_binding_id == collection_binding_id
        assert setting.created_user_id == created_user_id
        assert setting.updated_user_id == updated_user_id

    def test_app_annotation_setting_score_threshold_validation(self):
        """Test score threshold values."""
        # Arrange & Act
        setting_high = AppAnnotationSetting(
            app_id=str(uuid4()),
            score_threshold=0.95,
            collection_binding_id=str(uuid4()),
            created_user_id=str(uuid4()),
            updated_user_id=str(uuid4()),
        )
        setting_low = AppAnnotationSetting(
            app_id=str(uuid4()),
            score_threshold=0.5,
            collection_binding_id=str(uuid4()),
            created_user_id=str(uuid4()),
            updated_user_id=str(uuid4()),
        )

        # Assert
        assert setting_high.score_threshold == 0.95
        assert setting_low.score_threshold == 0.5


class TestAppAnnotationHitHistory:
    """Test suite for AppAnnotationHitHistory model."""

    def test_app_annotation_hit_history_creation(self):
        """Test creating an annotation hit history."""
        # Arrange
        app_id = str(uuid4())
        annotation_id = str(uuid4())
        message_id = str(uuid4())
        account_id = str(uuid4())

        # Act
        history = AppAnnotationHitHistory(
            app_id=app_id,
            annotation_id=annotation_id,
            source="api",
            question="What is AI?",
            account_id=account_id,
            score=0.95,
            message_id=message_id,
            annotation_question="What is AI?",
            annotation_content="AI stands for Artificial Intelligence.",
        )

        # Assert
        assert history.app_id == app_id
        assert history.annotation_id == annotation_id
        assert history.source == "api"
        assert history.question == "What is AI?"
        assert history.account_id == account_id
        assert history.score == 0.95
        assert history.message_id == message_id
        assert history.annotation_question == "What is AI?"
        assert history.annotation_content == "AI stands for Artificial Intelligence."

    def test_app_annotation_hit_history_score_values(self):
        """Test annotation hit history with different score values."""
        # Arrange & Act
        history_high = AppAnnotationHitHistory(
            app_id=str(uuid4()),
            annotation_id=str(uuid4()),
            source="api",
            question="Test",
            account_id=str(uuid4()),
            score=0.99,
            message_id=str(uuid4()),
            annotation_question="Test",
            annotation_content="Content",
        )
        history_low = AppAnnotationHitHistory(
            app_id=str(uuid4()),
            annotation_id=str(uuid4()),
            source="api",
            question="Test",
            account_id=str(uuid4()),
            score=0.6,
            message_id=str(uuid4()),
            annotation_question="Test",
            annotation_content="Content",
        )

        # Assert
        assert history_high.score == 0.99
        assert history_low.score == 0.6


class TestSiteModel:
    """Test suite for Site model."""

    def test_site_creation_with_required_fields(self):
        """Test creating a site with required fields."""
        # Arrange
        app_id = str(uuid4())

        # Act
        site = Site(
            app_id=app_id,
            title="Test Site",
            default_language="en-US",
            customize_token_strategy="uuid",
        )

        # Assert
        assert site.app_id == app_id
        assert site.title == "Test Site"
        assert site.default_language == "en-US"
        assert site.customize_token_strategy == "uuid"

    def test_site_creation_with_optional_fields(self):
        """Test creating a site with optional fields."""
        # Arrange & Act
        site = Site(
            app_id=str(uuid4()),
            title="Test Site",
            default_language="en-US",
            customize_token_strategy="uuid",
            icon_type=IconType.EMOJI,
            icon="🌐",
            icon_background="#0066CC",
            description="Test site description",
            copyright="© 2024 Test",
            privacy_policy="https://example.com/privacy",
        )

        # Assert
        assert site.icon_type == IconType.EMOJI
        assert site.icon == "🌐"
        assert site.icon_background == "#0066CC"
        assert site.description == "Test site description"
        assert site.copyright == "© 2024 Test"
        assert site.privacy_policy == "https://example.com/privacy"

    def test_site_custom_disclaimer_setter(self):
        """Test site custom_disclaimer setter."""
        # Arrange
        site = Site(
            app_id=str(uuid4()),
            title="Test Site",
            default_language="en-US",
            customize_token_strategy="uuid",
        )

        # Act
        site.custom_disclaimer = "This is a test disclaimer"

        # Assert
        assert site.custom_disclaimer == "This is a test disclaimer"

    def test_site_custom_disclaimer_exceeds_limit(self):
        """Test site custom_disclaimer with excessive length."""
        # Arrange
        site = Site(
            app_id=str(uuid4()),
            title="Test Site",
            default_language="en-US",
            customize_token_strategy="uuid",
        )
        long_disclaimer = "x" * 513  # Exceeds 512 character limit

        # Act & Assert
        with pytest.raises(ValueError, match="Custom disclaimer cannot exceed 512 characters"):
            site.custom_disclaimer = long_disclaimer

    def test_site_generate_code(self):
        """Test Site.generate_code static method."""
        # Mock database query to return 0 (no existing codes)
        with patch("models.model.db.session.query") as mock_query:
            mock_query.return_value.where.return_value.count.return_value = 0

            # Act
            code = Site.generate_code(8)

            # Assert
            assert isinstance(code, str)
            assert len(code) == 8


class TestModelIntegration:
    """Test suite for model integration scenarios."""

    def test_complete_app_conversation_message_hierarchy(self):
        """Test complete hierarchy from app to message."""
        # Arrange
        tenant_id = str(uuid4())
        app_id = str(uuid4())
        conversation_id = str(uuid4())
        message_id = str(uuid4())
        created_by = str(uuid4())

        # Create app
        app = App(
            tenant_id=tenant_id,
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=True,
            created_by=created_by,
        )
        app.id = app_id

        # Create conversation
        conversation = Conversation(
            app_id=app_id,
            mode=AppMode.CHAT,
            name="Test Conversation",
            status="normal",
            from_source="api",
            from_end_user_id=str(uuid4()),
        )
        conversation.id = conversation_id

        # Create message
        message = Message(
            app_id=app_id,
            conversation_id=conversation_id,
            query="Test query",
            message={"role": "user", "content": "Test"},
            answer="Test answer",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
        )
        message.id = message_id

        # Assert
        assert app.id == app_id
        assert conversation.app_id == app_id
        assert message.app_id == app_id
        assert message.conversation_id == conversation_id
        assert app.mode == AppMode.CHAT
        assert conversation.mode == AppMode.CHAT

    def test_app_with_annotation_setting(self):
        """Test app with annotation setting."""
        # Arrange
        app_id = str(uuid4())
        collection_binding_id = str(uuid4())
        created_user_id = str(uuid4())

        # Create app
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=True,
            created_by=created_user_id,
        )
        app.id = app_id

        # Create annotation setting
        setting = AppAnnotationSetting(
            app_id=app_id,
            score_threshold=0.85,
            collection_binding_id=collection_binding_id,
            created_user_id=created_user_id,
            updated_user_id=created_user_id,
        )

        # Assert
        assert setting.app_id == app.id
        assert setting.score_threshold == 0.85

    def test_message_with_annotation(self):
        """Test message with annotation."""
        # Arrange
        app_id = str(uuid4())
        conversation_id = str(uuid4())
        message_id = str(uuid4())
        account_id = str(uuid4())

        # Create message
        message = Message(
            app_id=app_id,
            conversation_id=conversation_id,
            query="What is AI?",
            message={"role": "user", "content": "What is AI?"},
            answer="AI stands for Artificial Intelligence.",
            message_unit_price=Decimal("0.0001"),
            answer_unit_price=Decimal("0.0002"),
            currency="USD",
            from_source="api",
        )
        message.id = message_id

        # Create annotation
        annotation = MessageAnnotation(
            app_id=app_id,
            conversation_id=conversation_id,
            message_id=message_id,
            question="What is AI?",
            content="AI stands for Artificial Intelligence.",
            account_id=account_id,
        )

        # Assert
        assert annotation.app_id == message.app_id
        assert annotation.conversation_id == message.conversation_id
        assert annotation.message_id == message.id

    def test_annotation_hit_history_tracking(self):
        """Test annotation hit history tracking."""
        # Arrange
        app_id = str(uuid4())
        annotation_id = str(uuid4())
        message_id = str(uuid4())
        account_id = str(uuid4())

        # Create annotation
        annotation = MessageAnnotation(
            app_id=app_id,
            question="What is AI?",
            content="AI stands for Artificial Intelligence.",
            account_id=account_id,
        )
        annotation.id = annotation_id

        # Create hit history
        history = AppAnnotationHitHistory(
            app_id=app_id,
            annotation_id=annotation_id,
            source="api",
            question="What is AI?",
            account_id=account_id,
            score=0.92,
            message_id=message_id,
            annotation_question="What is AI?",
            annotation_content="AI stands for Artificial Intelligence.",
        )

        # Assert
        assert history.app_id == annotation.app_id
        assert history.annotation_id == annotation.id
        assert history.score == 0.92

    def test_app_with_site(self):
        """Test app with site."""
        # Arrange
        app_id = str(uuid4())

        # Create app
        app = App(
            tenant_id=str(uuid4()),
            name="Test App",
            mode=AppMode.CHAT,
            enable_site=True,
            enable_api=True,
            created_by=str(uuid4()),
        )
        app.id = app_id

        # Create site
        site = Site(
            app_id=app_id,
            title="Test Site",
            default_language="en-US",
            customize_token_strategy="uuid",
        )

        # Assert
        assert site.app_id == app.id
        assert app.enable_site is True
